package system

import (
	"fmt"
	"os"
	"regexp"
	"syscall"
	"unsafe"
)

var (
	IpReg = regexp.MustCompile(`(\d+)\.(\d+)\.(\d+)\.(\d+)`)
)

func LocalIPV4() (string, error) {
	aList, err := getAdapterList()
	if err != nil {
		return "", err
	}
	for ai := aList; ai != nil; ai = ai.Next {
		ipl := &ai.IpAddressList
		gwl := &ai.GatewayList
		// gwN := 0
		for ; gwl != nil; gwl = gwl.Next {
			// gwN += 1
			// fmt.Printf("%d %s (%s)\n", gwN, gwl.IpAddress, gwl.IpMask)
			ip := fmt.Sprintf("%s", gwl.IpAddress)
			ip = IpReg.FindAllString(ip, 1)[0]
			if ip != "0.0.0.0" {
				goto IP
			}
		}
		continue
	IP:
		// ipN := 0
		for ; ipl != nil; ipl = ipl.Next {
			// ipN += 1
			// fmt.Printf("%d %s (%s)\n", ipN, ipl.IpAddress, ipl.IpMask)
			ip := fmt.Sprintf("%s", ipl.IpAddress)
			ip = IpReg.FindAllString(ip, 1)[0]
			fmt.Println(ip)
			if ip != "0.0.0.0" {
				return ip, nil
			}
		}
	}
	return "", EmptyIPV4Err
}

func IsLocalIP(ip string) (bool, error) {
	addr, _ := net.LookupIP(ip)
	m := make(map[string]net.IP, len(addr))
	for index, ip := range addr {
		m[ip.String()] = addr[index]
	}
	aList, err := getAdapterList()
	if err != nil {
		return false, err
	}
	for ai := aList; ai != nil; ai = ai.Next {
		ipl := &ai.IpAddressList
		gwl := &ai.GatewayList
		// gwN := 0
		for ; gwl != nil; gwl = gwl.Next {
			// gwN += 1
			// fmt.Printf("%d %s (%s)\n", gwN, gwl.IpAddress, gwl.IpMask)
			ip := fmt.Sprintf("%s", gwl.IpAddress)
			ip = IpReg.FindAllString(ip, 1)[0]
			if ip != "0.0.0.0" {
				goto IP
			}
		}
		continue
	IP:
		// ipN := 0
		for ; ipl != nil; ipl = ipl.Next {
			// ipN += 1
			// fmt.Printf("%d %s (%s)\n", ipN, ipl.IpAddress, ipl.IpMask)
			ip := fmt.Sprintf("%s", ipl.IpAddress)
			ip = IpReg.FindAllString(ip, 1)[0]
			fmt.Println(ip)
			_, ok := m[ip]
			if ok {
				return true, nil
			}
		}
	}
	return false, nil
}

func getAdapterList() (*syscall.IpAdapterInfo, error) {
	b := make([]byte, 1000)
	l := uint32(len(b))
	a := (*syscall.IpAdapterInfo)(unsafe.Pointer(&b[0]))
	err := syscall.GetAdaptersInfo(a, &l)
	if err == syscall.ERROR_BUFFER_OVERFLOW {
		b = make([]byte, l)
		a = (*syscall.IpAdapterInfo)(unsafe.Pointer(&b[0]))
		err = syscall.GetAdaptersInfo(a, &l)
	}
	if err != nil {
		return nil, os.NewSyscallError("GetAdaptersInfo", err)
	}
	return a, nil
}
